﻿using System;
using System.Globalization;
using AdvancedGod.People;

namespace AdvancedGod.Generation
{
  /// <summary>
  /// Serves god console: generates random peoples and fields
  /// </summary>
  public class RandomGenerator
  {
    #region private consts

    /// <summary>
    /// Minimal human's age
    /// </summary>
    private const int MinAge = 15;

    /// <summary>
    /// Maximal human's age
    /// </summary>
    private const int MaxAge = 31;
    #endregion

    #region private static vars
    /// <summary>
    /// Collection of male names
    /// </summary>
    private static readonly string[] MaleNames = 
        {
            Names.Oleg, Names.Patrik, Names.Hamlet, Names.Roger, Names.Sauron,
            Names.Zavulon, Names.Leonid, Names.Anton
        };

    /// <summary>
    /// Collection of emale names
    /// </summary>
    private static readonly string[] FemaleNames = 
        {
            Names.Olga, Names.Anna, Names.Alexandra, Names.Anastasiya,
            Names.Olesya, Names.Tatiana, Names.Mariya, Names.Marianna
        };

    /// <summary>
    /// Single intance of class
    /// </summary>
    private static RandomGenerator instance;
    #endregion

    #region private vars
    /// <summary>
    /// Randomizer for human creation
    /// </summary>
    private readonly Random random = new Random();
    #endregion



    #region private methods
    /// <summary>
    /// Constructor (hided)
    /// </summary>
    private RandomGenerator()
    {
    }

    /// <summary>
    /// Generates random surname for humans
    /// </summary>
    /// <param name="sex">human's sex</param>
    /// <returns>random surname corresponding to human's sex</returns>
    private string GenerateSurname(Sex sex)
    {
      string name = GenerateMaleName();
      return GenerateSurname(name, sex);
    }

    /// <summary>
    /// Generates random male name
    /// </summary>
    /// <returns>random male name</returns>
    private string GenerateMaleName()
    {
      int index = random.Next(0, MaleNames.Length);
      return MaleNames[index];
    }

    /// <summary>
    /// Generates random female name
    /// </summary>
    /// <returns>random female name</returns>
    private string GenerateFemaleName()
    {
      int index = random.Next(0, FemaleNames.Length);
      return FemaleNames[index];
    }

    /// <summary>
    /// Generates random average mark
    /// </summary>
    /// <returns>random average mark</returns>
    private double GenerateAvgMark()
    {
      double randomDouble = random.NextDouble();
      return randomDouble * 
        (Botan.MaximumAverageMark - Botan.MinimumAverageMark) +
        Botan.MinimumAverageMark;
    }

    /// <summary>
    /// Generate random age
    /// </summary>
    /// <returns>random age </returns>
    private int GenerateAge()
    {
      return random.Next(MinAge, MaxAge);
    }
    /// <summary>
    /// Create Smart Girl with random values in fields
    /// </summary>
    /// <returns>new Smart Girl with random values in fields</returns>
    private Human CreateSmartGirl()
    {
      string name = GenerateFemaleName();
      return new SmartGirl(name)
      {
        Surname = GenerateSurname(Sex.Female),
        Age = GenerateAge()
      };

    }

    /// <summary>
    /// Create Pretty Girl with random values in fields
    /// </summary>
    /// <returns>new Pretty Girl with random values in fields</returns>
    private Human CreatePrettyGirl()
    {
      string name = GenerateFemaleName();
      return new PrettyGirl(name)
      {
        Surname = GenerateSurname(Sex.Female),
        Age = GenerateAge()
      };
    }

    /// <summary>
    /// Create Girl with random values in fields
    /// </summary>
    /// <returns>new Girl with random values in fields</returns>
    private Human CreateGirl()
    {
      string name = GenerateFemaleName();
      return new Girl(name)
      {
        Surname = GenerateSurname(Sex.Female),
        Age = GenerateAge()
      };
    }

    /// <summary>
    /// Create Botan with random values in fields
    /// </summary>
    /// <returns>new Botan with random values in fields</returns>
    private Human CreateBotan()
    {
      string name = GenerateMaleName();
      return new Botan(name)
      {
        Surname = GenerateSurname(Sex.Male),
        Age = GenerateAge(),
        AveargeMark = GenerateAvgMark()
      };
    }

    /// <summary>
    /// Create Student with random values in fields
    /// </summary>
    /// <returns>new Student with random values in fields</returns>
    private Human CreateStudent()
    {
      string name = GenerateMaleName();
      return new Student(name)
      {
        Surname = GenerateSurname(Sex.Male),
        Age = GenerateAge()
      };
    }

    #endregion

    #region public static properties
    /// <summary>
    /// Getter for single instance of class
    /// </summary>
    public static RandomGenerator Instance
    {
      get { return instance ?? (instance = new RandomGenerator()); }
    }
    #endregion

    #region public methods
    /// <summary>
    /// Generates surname by parent name and expected human's sex
    /// </summary>
    /// <param name="parentName">parent's name</param>
    /// <param name="sex">sex of human, for which surname generates</param>
    /// <returns>surname corresponding to father name and human's sex</returns>
    public string GenerateSurname(string parentName, Sex sex)
    {
      string suffix = sex == Sex.Male ?
        Humans.SurnameManSuffix :
        Humans.SurnameWomanSuffix;
      return string.Format(CultureInfo.CurrentCulture, Humans.SurnameCreation, parentName, suffix);
    }

    /// <summary>
    /// Creates random human
    /// </summary>
    /// <returns>new Human with random values in fields</returns>
    public Human CreateRandomHuman()
    {
      int type = random.Next(0, 5);
      switch (type)
      {
        case 0:
        return CreateStudent();
        case 1:
        return CreateBotan();
        case 2:
        return CreateGirl();
        case 3:
        return CreatePrettyGirl();
        default:
        return CreateSmartGirl();
      }
    }
    #endregion


  }
}
